local redis = require "resty.redis";
local cjson = require "cjson"
local find = string.find
local sub = string.sub
----local logger=logger;

local setmetatable=setmetatable;
local _M={_VERSION="1.0"};
local _mt={__index=_M};
setmetatable(_M,_mt);



function _M:generate_tid()
	local date = require 'resty.date';
	local now = date(false);
	local val = now:fmt("%Y%m%d%H%M%S%\f");
	local timeVal = string.sub(val,1,string.find(val,"%.")-1)

	local num1 = math.random(0, 9)
	local num2 = math.random(0, 9)

	local tid = "38"..timeVal..num1..num2;
	return tid;
end

function _M:output_plain(msg)
	ngx.status = ngx.HTTP_OK
	ngx.header["Content-type"] = "text/plain;charset=UTF-8"
	ngx.header["Cache-Control"]="no-cache"
        ngx.header["Access-Control-Allow-Headers"]= "x-requested-with"
        ngx.header["Access-Control-Allow-Methods"]= "POST, GET"
        ngx.header["Access-Control-Allow-Origin"]= "*"
	ngx.say(msg)
  --ngx.req.discardBody();
	ngx.exit(0)
end

function _M:output_json(jsonMsg)  
	ngx.status = ngx.HTTP_OK
	ngx.header["Content-type"] = "application/json;charset=UTF-8";	
    ngx.header["Access-Control-Allow-Headers"]= "x-requested-with"
    ngx.header["Access-Control-Allow-Methods"]= "POST, GET"
    ngx.header["Access-Control-Allow-Origin"]= "*"
	ngx.say(jsonMsg)
  --ngx.req.discardBody();
	ngx.exit(0)
end

function _M:output_jpeg(jsonMsg)  
	ngx.status = ngx.HTTP_OK
	ngx.header["Content-type"] = "image/jpeg";	
    ngx.header["Access-Control-Allow-Headers"]= "x-requested-with"
    ngx.header["Access-Control-Allow-Methods"]= "POST, GET"
    ngx.header["Access-Control-Allow-Origin"]= "*"
	ngx.say(jsonMsg)
  --ngx.req.discardBody();
	ngx.exit(0)
end

function _M:output_system_busy()
	ngx.status = ngx.HTTP_OK
	ngx.header["Content-type"] = "text/plain;charset=UTF-8"
	ngx.header["Cache-Control"]="no-cache"
        ngx.header["Access-Control-Allow-Headers"]= "x-requested-with"
        ngx.header["Access-Control-Allow-Methods"]= "POST, GET"
        ngx.header["Access-Control-Allow-Origin"]= "*"
	ngx.say('{state=3809001,msg="系统繁忙，请稍后再试",data=nil}')
  --ngx.req.discardBody();
	ngx.exit(0)
end

function _M:get_req_args_all()
	local last_req_args = {};
	ngx.req.read_body();

	for k,v in pairs(ngx.req.get_uri_args()) do
		last_req_args[k] = v;
	end
	for k,v in pairs(ngx.req.get_post_args()) do
		last_req_args[k] = v;
	end


	if not last_req_args then
		last_req_args = {};
	end
	return last_req_args;
end;

function _M:get_req_param(key,req_args)
	local val; 
	if req_args then
		val = req_args[key];
	end;
	return val;
end

function _M:checkGroupStatus(t_id,userId,actionId,qcode)
	local http = require("resty.http") ;
	local httpc = http:new();
	if not actionId or actionId == ngx.null or actionId == nil then
		actionId="";
	end;
	local tempParams = "t_id="..t_id.."&userid="..(userId).."&actionid="..actionId.."&qcode="..qcode;
	local resp,err =  httpc:request_uri( ngx.var.market , {
		method = "POST",
		path = "/market/bet/checkgroupstatus.do?"..tempParams,
		headers={["X-Real-IP"]=ngx.var.remote_addr,["X-Forwarded-For"]=ngx.var.proxy_add_x_forwarded_for}
	})
	return resp,err;
end

function _M:setBetPrizeAddr(t_id,addrid,userid,req_args)
	local http = require("resty.http") ;
	local cjson = require("cjson")
	req_args = req_args or {};
	local httpc = http:new();
	local tempParams = "t_id="..t_id.."&addressId="..addrid;
	local resp,err =  httpc:request_uri( ngx.var.uic , {
		method = "POST",
		path = "/uic/user/addressInfo.do?"..tempParams,
		headers={["X-Real-IP"]=ngx.var.remote_addr,["X-Forwarded-For"]=ngx.var.proxy_add_x_forwarded_for}
	})
	if err then
		ngx.log(ngx.ERR,logger.formatMsg("connect uic error:",err))
	elseif resp.status ~= 200 then
		ngx.log(ngx.ERR,logger.formatMsg("find no address"..addrid))
	else
		local obj = cjson.decode(resp.body);
		ngx.log(ngx.INFO,logger.formatMsg(resp.body));
		local uicUserId = ''..obj.data.userId
		if obj and obj.data and obj.data ~= nil then
			if uicUserId ~= userid then		
				local result = cjson.encode({state=1,msg="请选择自己的收货地址",data=nil});
				self:output_json(result)
			end;
			if obj.data.addressId then
				req_args["ship_id"] = obj.data.addressId;
			end
			if obj.data.lastUpdateTime then
				req_args["ship_updatetime"] = obj.data.lastUpdateTime;   --(ngx.escape_uri(obj.data.lastUpdateTime));
			end

			req_args["ship_area"] = self:packAddrs(obj.data.provinceName,obj.data.cityName,obj.data.areaName);
			req_args["ship_area_code"] = self:packAddrs(obj.data.provinceId,obj.data.cityId,obj.data.areaId);
			if obj.data.areaDesc then
				--- 这个地方没写错，就是这样写的
				req_args["ship_address"] = obj.data.areaDesc;
			end
			if obj.data.contentPhone then
				req_args["ship_mobile"] = obj.data.contentPhone;
			end
			if obj.data.contentName then
				req_args["ship_name"] = obj.data.contentName;
			end
			if obj.data.zipCode then
				req_args["ship_zip_code"] = obj.data.zipCode;
			end
		end;
	end
	return req_args;
end

function _M:packAddrs(province,city,area)
	local result = '';
	if  province then 
		result = result..province
	end
	if city then
		result = result..","..city
	end
	if area then
		result = result..","..area
	end
	return result;

end


function _M:getClientType(appname)
	local client;
	if  appname and type(appname) == 'string'  then
		appname = string.upper(appname);
		if ngx.re.match(appname,"IOS","o") then  
			client = 1;
		elseif ngx.re.match(appname,"ANDROID","o") then
			client = 2;
		elseif ngx.re.match(appname,"WAP","o") then
			client = 3;
		elseif ngx.re.match(appname,"WX","o") then
			client = 4;
		end
	end
	return client;
end

function _M:isWapRequest(appname)
	local flag = true;
	if  appname and type(appname) == 'string'  then
		appname = string.upper(appname);
		if ngx.re.match(appname,"IOS","o") then
			flag = false;
		elseif ngx.re.match(appname,"ANDROID","o") then
			flag = false;
		end
	end
	return flag;
end

function _M:getSortedParamsStr(request_args_all)
	local result='' ;
	if request_args_all and type(request_args_all) == 'table' then
		local bufferSort='';
		for k,v in pairs(request_args_all) do
			if type(v)=='string' then
				bufferSort = bufferSort..k.."="..v.."△";
			elseif type(v)=='table' then
				for x,y in pairs(v) do
					bufferSort = bufferSort..k.."="..y.."△";
				end
			end
		end     
		ngx.log(ngx.INFO,logger.formatMsg("请求的参数paramsize=",table.getn(request_args_all)," bufferSort=",bufferSort))
		local requestParams;
		if string.len(bufferSort)>0  then
			local paramStr = string.sub(bufferSort,1,-2)
			if string.sub(paramStr,-1,-1)==','  then
				paramStr = string.sub(bufferSort,1,-2)
			end
			requestParams = self:split(bufferSort,"△");
			table.sort(requestParams);
			for _,v in pairs(requestParams) do
				result = result..v;
			end;
		end
	end 
	return result;
end

function _M:close_redis(red)  
	if not red then  
		return  
	end  
	--释放连接(连接池实现)  
	local pool_max_idle_time = 10000 --毫秒  
	local pool_size = 100 --连接池大小  
	local ok, err = red:set_keepalive(pool_max_idle_time, pool_size)  
	if not ok then  
		ngx.say("set keepalive error : ", err)  
	end  
end  

function _M:split(str, sep)
	local arr = {}
	local pos = 0

	if type(str) ~= 'string' then
		return nil, 'invalid string'
	end
	if type(sep) == 'nil' then
		sep = '.'
	elseif type(sep) ~= 'string' and type(sep) ~= 'number' then
		return nil, 'invalid separator'
	end

	for b, e in function() return find(str, sep, pos) end do
	if sep == '.' then
		arr[#arr + 1] = sub(str, pos, b)
	else
		arr[#arr + 1] = sub(str, pos, b - 1)
	end
	pos = e + 1
end
	if sep ~= '.' then
		arr[#arr + 1] = sub(str, pos)
	end
		return arr
 end


function _M:querySentinelMaster(redis_url,sentinel_name)
  local redis_connector = require "resty.redis.connector"
  local rc = redis_connector.new()
  local sentinel, err = rc:connect{url = redis_url }
  if not sentinel then
                ngx.log(ngx.ERR,logger.formatMsg("failed to connect: ", err))
                return
            end
  local redis_sentinel = require "resty.redis.sentinel"
  local master, err = redis_sentinel.get_master(sentinel,sentinel_name)
    if not master then
        ngx.log(ngx.ERR,logger.formatMsg("failed to get sentinel server:",err))
        return
    else
        return master.host,master.port
    end
   sentinel:close()
   return
end
-- 找到接入层URL地址对应的内部系统的URL地址
function _M:getRealyUrl(pUrl,urlMapConfig)  
	if not pUrl then  
		return  
	end  
	local retValue={};
	ngx.log(ngx.INFO,logger.formatMsg("pUrl="..pUrl));
	local t_splited_url = self:split(pUrl,"/");
	local findServerPath =  t_splited_url[1].."/"..t_splited_url[2].."/"..t_splited_url[3].."/";
	ngx.log(ngx.INFO,logger.formatMsg("=================================== findServerPath :"..findServerPath));
	local serverPath = urlMapConfig:get(findServerPath);
	ngx.log(ngx.INFO,logger.formatMsg("=================================== find server :"..serverPath));
	--ngx.exit(0);

	local resultServerRoot;	
	local m, err = ngx.re.match(serverPath, "(.*)/");
	if m then
		resultServerRoot = m[0];
	else
		local result = cjson.encode({state=4020002,msg="系统繁忙，请稍后再试",data=nil});
		ngx.log(ngx.ERR,logger.formatMsg("cannot parse the corrent server  path."));
		self:output_plain(result);
	end
	retValue["resultServerRoot"]=resultServerRoot;
	local namespaceFirst = ngx.re.gsub(serverPath,resultServerRoot,"");
	if not namespaceFirst then
		local result = cjson.encode({state=4020002,msg="系统繁忙，请稍后再试",data=nil});
		ngx.log(ngx.ERR,logger.formatMsg("cannot parse the corrent server second path."));
		self:output_plain(result);
	end;
	 local realUrl= "/"..namespaceFirst.."/"..(t_splited_url[4]).."/"..(t_splited_url[5])..".do";
	 retValue["realUrl"]=realUrl;
	 return  retValue;
end  
-- 处理检查用户是否登录
function _M:processIsLogin()
	
	local uri = ngx.var.uri;
	local token = ngx.req.get_headers()["token"]
	local config = ngx.shared.config;
	if not token then
		local last_req_args = self:get_req_args_all();
		token = self:get_req_param("token",last_req_args);
	end

	local sentinel_redis_url=config:get("redis.url")
	local sentinel_redis_server=config:get("sentinel_server_portal")
	ngx.log(ngx.INFO,logger.formatMsg("query setninel master by url="..sentinel_redis_url..",server="..sentinel_redis_server))
	local sentinel_master_ip,sentinel_master_port = self:querySentinelMaster(sentinel_redis_url,sentinel_redis_server);
	if not sentinel_master_ip or not sentinel_master_port then
		ngx.log(ngx.ERR,logger.formatMsg("connect sentinel failed:", err))
    --ngx.req.discardBody();
		ngx.exit(ngx.HTTP_SERVICE_UNAVAILABLE)
		return
	else
		ngx.log(ngx.INFO,logger.formatMsg("master server: ip="..sentinel_master_ip..",port="..sentinel_master_port))
	end

	local pool_max_idle_time = config:get("redis.maxActive")  ---------------- 毫秒  
	local pool_size = config:get("redis.poolSize") -------------------连接池大小
	local redisIp= sentinel_master_ip;
	local redisPort=sentinel_master_port;

	local cache = redis.new()
	local ok, err = cache.connect(cache,redisIp,redisPort)
	local redis_timeout = config:get("redis.timeout")
	cache:set_timeout(redis_timeout)
	if not ok then
		ngx.log(ngx.ERR,logger.formatMsg("failed to connect:", err))
    --ngx.req.discardBody();
		ngx.exit(ngx.HTTP_SERVICE_UNAVAILABLE)
		return
	end
	local last_req_args = self:get_req_args_all();
	if not token then
		token = self:get_req_param("token",last_req_args);
	end
	if ngx.var.APP_DEBUG_LOG== "true" then ngx.log(ngx.DEBUG,logger.formatMsg("token=",token)); end
	local userId,phone,res,err;
	---用于判断当前登录用户类型：1=未知用户，2=微店用户，3=生活用户。
	local _userType =1;
	if token then
		res,err = cache:hgetall(token)
		if err then
			ngx.log(ngx.ERR,logger.formatMsg("failed to get token: ", err))
		elseif not res then
			ngx.log(ngx.WARN,logger.formatMsg("token not found."))
		else
			local h = cache:array_to_hash(res);
			phone = h.phone;
			userId = h.userId;
			ngx.ctx.userId = h.userId;
			--判断当期登录的用户类型。
			--cp:开头的token是生活系统产生的，当前用户是生活的用户
			local _startIndex,_endIndex=string.find(token,"cp:");
			if _starIndex==1 and _endIndex==3 then
				_userType=3;				
			else
			--p:开头的token是微店系统产生的，当前用户是微店用户
				local _starIndex,_endIndex=string.find(token,"p:");
				if  _starIndex==1 and _endIndex==2 then
					_userType=2;
					ngx.ctx.shopId=h.shopId;
				end;
			end;
			ngx.ctx._userType=_userType;
			ngx.ctx.nickname = h.nickName;
			ngx.ctx.logourl = h.userLogo;
			ngx.ctx.phone = h.phone;
		end;
		self:close_redis(cache);
	end

	if (not token or not ngx.ctx.userId ) then
		local result = cjson.encode({state=3829201,msg="用户未登录,请登录",data=nil});
		self:output_plain(result);
	end
end

return _M;
